﻿using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using Caliburn.Core;
using System.Disposables;

namespace IronCommander.Utils
{
    public class ValueWithHistory<T> : PropertyChangedBase, INotifyPropertyChanging
    {
        readonly List<T> history = new List<T>();
        readonly object syncObj = new object();
        int current = -1;

        public bool IsInitialized { get { lock (syncObj) return current >= 0; } }

        public T Value
        {
            get { lock (syncObj) return history[current]; }
            set
            {
                lock (syncObj)
                {
                    if (IsInitialized && EqualityComparer<T>.Default.Equals(Value, value))
                        return;

                    if (IsInitialized && CanRedo)
                        history.RemoveRange(current + 1, history.Count - current - 1);

                    using (BeginUpdateValue())
                    {
                        history.Add(value);
                        current++;
                    }
                }
            }
        }

        IDisposable BeginUpdateValue()
        {
            PropertyChanging.Raise(this, "Value");
            return Disposable.Create(() => NotifyOfPropertyChange(() => Value));
        }

        public bool CanUndo
        {
            get { lock (syncObj) return current > 0; }
        }

        public bool CanRedo
        {
            get { lock (syncObj) return current < history.Count - 1; }
        }

        public bool TryUndo()
        {
            lock (syncObj)
            {
                if (!CanUndo)
                    return false;

                using (BeginUpdateValue())
                    current--;

                return true;
            }
        }

        public bool TryRedo()
        {
            lock (syncObj)
            {
                if (!CanRedo)
                    return false;

                using (BeginUpdateValue())
                    current++;

                return true;
            }
        }

        public event PropertyChangingEventHandler PropertyChanging;
    }
}
